/*
 * BusAPI.h
 *
 *  Created on: Jul 22, 2013
 *      Author: m
 */

#ifndef BUSAPI_H_
#define BUSAPI_H_

#include "application_common.h"
#include "messages.h"
#include "Visitor.h"
#include "ConcurrentMessageQueue.h"

namespace application
{

class BusAPI
{
public:
    BusAPI()
    {
    }

    virtual ~BusAPI()
    {
    }

    bool takeEntranceBus( Visitor &visitor )
    {
        return this->takeBus( visitor, ENTRANCE_BUS );
    }

    bool takeExitBus( Visitor &visitor )
    {
        return this->takeBus( visitor, EXIT_BUS );
    }

protected:

    bool takeBus( Visitor &visitor, busType busType )
    {
        std::string loadingAddress;
        std::string unloadingAddress;
        std::string unloadRequestAddress;
        bool destinationReached = false;

        // Abro el canal para recibir el mensaje de que puedo subir al bus
        if ( busType == ENTRANCE_BUS )
        {
            loadingAddress = visitor.getTicket().m_entranceBusPass.m_loadingAddress;
        }
        else
        {
            loadingAddress = visitor.getTicket().m_exitBusPass.m_loadingAddress;
        }

        std::clog << "Waiting LoadRequest from: " << loadingAddress << std::endl;

        communication::ConcurrentMessageQueue<LoadRequest> loadRequestQueue( loadingAddress );

        // Espero que el bus indique que el pasajero puede subir
        LoadRequest msg = loadRequestQueue.get();

        visitor.getOnTheBus();

        // Indico que el pasajero sube al bus

        std::clog << "Sending LoadReply to: " << loadingAddress << std::endl;

        std::string loadReplyAddress = msg.m_replyTo.m_data;

        communication::ConcurrentMessageQueue<LoadReply> loadReplyQueue( loadReplyAddress );

        unloadRequestAddress = std::string(msg.m_busName.m_data) + ".unload." + visitor.getId();

        LoadReply loadReply;
        loadReply.m_visitor = visitor.serialize();
        loadReply.m_replyTo = unloadRequestAddress;

        loadReplyQueue.put( loadReply );

        // Esperar la respuesta del bus

        std::clog << "Waiting UnloadRequest from: " << unloadRequestAddress << std::endl;

        communication::ConcurrentMessageQueue<UnloadRequest> unloadRequestQueue( unloadRequestAddress );

        UnloadRequest unloadRequest;

        unloadRequest = unloadRequestQueue.get();

        // Verificar si el pasajero viajo o no
        std::string unloadReplyQueueName;

        if ( unloadRequest.m_reason == UNLOAD_DESTINATION_REACHED )
        {
            destinationReached = true;

            visitor.getOffTheBus();

            // Notifico que el pasajero se bajo del bus

            // Para ello primero obtengo el nombre de la cola en la que debo responder
            if ( busType == ENTRANCE_BUS )
            {
                unloadReplyQueueName = unloadRequest.m_ticket.m_entranceBusPass.m_unloadingAddress.m_data;
            }
            else
            {
                unloadReplyQueueName = unloadRequest.m_ticket.m_exitBusPass.m_unloadingAddress.m_data;
            }

            communication::ConcurrentMessageQueue<UnloadReply> unloadReplyQueue( unloadReplyQueueName );

            UnloadReply unloadReply;
            unloadReply.m_visitor = visitor.serialize();

            std::clog << "Sending Unload Reply to: " << unloadReplyQueueName << std::endl;

            unloadReplyQueue.put( unloadReply );
        }


        return destinationReached;
    }
};

} /* namespace application */
#endif /* BUSAPI_H_ */
